﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Galaktika.BI.Silverlight.Services;

namespace Galaktika.BI.Silverlight.ClientApp.Web.Runtime.DataAccess
{
    public class QueryManager
    {
        private QueryManager()
        {
        }

        public static void Create()
        {
            if (HttpContext.Current != null &&
                HttpContext.Current.Session != null)
            {
                HttpContext.Current.Application[InstanceId] = new QueryManager();
            }
        }

        private static string InstanceId
        {
            get
            {
                return HttpContext.Current.Session.SessionID + COMMAND_MANAGER_HOLDER;
            }
        }

        public static void Dispose()
        {
            if (HttpContext.Current != null &&
                HttpContext.Current.Session != null)
            {
                HttpContext.Current.Application.Remove(InstanceId);
            }
        }

        private const string COMMAND_MANAGER_HOLDER = "CommandManangerHolder";
        public static QueryManager Current
        {
            get
            {
                if (HttpContext.Current != null &&
                    HttpContext.Current.Session != null)
                {
                    return HttpContext.Current.Application[InstanceId] as QueryManager;

                    //var mgr = HttpContext.Current.Session.Contents[COMMAND_MANAGER_HOLDE] as QueryManager;
                    //if (mgr == null)
                    //{
                    //    mgr = new QueryManager();
                    //    HttpContext.Current.Session.Contents[COMMAND_MANAGER_HOLDER] = mgr;
                    //}

                    //return mgr;
                }

                return null;
            }
        }

        private class QueryDescriptor
        {
            public QueryDescriptor(
                string id,
                Func<InvokeResultSchema> query,
                Func<bool> isCancelable,
                Func<bool> doCancel)
            {
                this.Id = id;
                this.Query = query;
                this.IsCancelable = isCancelable;
                this.DoCancel = doCancel;
            }

            public readonly string Id;
            public readonly Func<InvokeResultSchema> Query;
            public readonly Func<bool> DoCancel;
            public readonly Func<bool> IsCancelable;
            public QueryExecutionState State = QueryExecutionState.Queued;
        }

        private readonly Dictionary<string, QueryDescriptor> m_Queries = new Dictionary<string, QueryDescriptor>();
        public InvokeResultSchema ExecuteQuery(
            string id,
            Func<InvokeResultSchema> query,
            Func<bool> isCancelable)
        {
            return this.ExecuteQuery(id, query, isCancelable, null);
        }

        public InvokeResultSchema ExecuteQuery(
            string id,
            Func<InvokeResultSchema> query,
            Func<bool> isCancelable,
            Func<bool> doCancel)
        {
            var desc = new QueryDescriptor(id, query, isCancelable, doCancel);
            if (!string.IsNullOrEmpty(id))
            {
                lock (m_Queries)
                {
                    m_Queries.Add(id, desc);
                }
            }


            InvokeResultSchema res = null;
            try
            {
                desc.State = QueryExecutionState.Executing;
                res = desc.Query();
                desc.State = QueryExecutionState.Done;
            }
            catch
            {
                desc.State = QueryExecutionState.Canceled;
                throw;
            }

            return res;
        }

        public bool TryCancel(string id)
        {
            QueryDescriptor desc;
            lock (m_Queries)
            {
                m_Queries.TryGetValue(id, out desc);
            }

            if (desc != null && desc.IsCancelable())
            {
                desc.DoCancel();
            }

            return false;
        }

        public IEnumerable<QueryStateDescriptor> ExtractQueryDescriptors()
        {
            var res = new List<QueryStateDescriptor>();
            List<QueryDescriptor> queriesCopy;
            lock (m_Queries)
            {
                queriesCopy = new List<QueryDescriptor>(m_Queries.Values);
            }

            foreach (var desc in queriesCopy)
            {
                res.Add(new QueryStateDescriptor(desc.Id, desc.State));

                if (desc.State == QueryExecutionState.Done ||
                    desc.State == QueryExecutionState.Canceled)
                {
                    lock (m_Queries)
                    {
                        m_Queries.Remove(desc.Id);
                    }
                }
            }

            return res;
        }
    }
}
